#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "class.h"
#include "ctype.h"

#define lock()
#define unlock()

static ClassType *used_class_type_head = NULL;

static void init_cobject_class(CObjectClass *vclass)
{
	if(vclass==NULL)
		return;
	
	vclass->destroy = cobject_destroy;
}

static void init_cobject(CObject *object)
{
	if(object==NULL)
		return;
	
	object->ref_counter = 1;
	printf("construct cobject\n");
}

u32 get_cobject_type(void)
{
	static u32 type = 0;
	
	if( type==0 )
	{
		static ClassInfo classinfo = 
		{
			"COBJECT",
				sizeof(CObject),
				sizeof(CObjectClass),
				(init_object_callback)init_cobject,
				(init_class_callback)init_cobject_class,
		};
		
		type = register_class_type(&classinfo, TOP_OBJECT_TYPE);
	}
	
	return type;
}

CObject* cobject_new(void)
{
	return (CObject*)g_object_new(COBJECT_TYPE);
}

void cobject_destroy(CObject *object)
{
	if(object !=NULL)
	{
		free(object);
		printf("destory cobject\n");
	}
}

/****************************************************************/

void init_class_type_list(void)
{
	memset(used_class_type_head, 0, sizeof(ClassType));
}

ClassType* get_class_type_node(void)
{
	ClassType *free_node = (ClassType*)malloc(sizeof(ClassType));
	memset(free_node, 0, sizeof(ClassType));
	return free_node;
}

u32 register_class_type(ClassInfo *classinfo, u32 parent_type)
{
	u32 type = 0;
	ClassType *current, *parent;
	
	parent = (ClassType *)parent_type;

	if( classinfo->name==NULL )
	{
		printf("register_class_type(): class name is NULL/n");
		return type;
	}
	
	lock();
	current = used_class_type_head;
	while(current)
	{
		if( strcmp(current->name, classinfo->name) == 0 )
		{
			printf("register_class_type(): class name is redefined/n");
			unlock();
			return type;
		}
		current = current->next;
	}
	
	current = get_class_type_node();
	if(current)
	{
		current->name = classinfo->name;
		current->parent = parent;
		current->object_size = classinfo->object_size;
		current->class_size = classinfo->class_size;
		current->init_class = classinfo->init_class;
		current->init_object = classinfo->init_object;
		current->vclass = (CObjectClass *)malloc(current->class_size);
		
		if( current->vclass == NULL )
		{
			printf("register_class_type(): malloc vclass failed/n");
		}
		
		memset( current->vclass, 0, current->class_size);
		
		if( parent )
		{
			memcpy(current->vclass, parent->vclass, parent->class_size);
		}
		
		current->vclass->class_type = (u32)current;
		
		if( current->init_class )
			current->init_class(current->vclass);
		
		current->next = used_class_type_head;
		used_class_type_head = current;
	}
	else
	{
		printf("register_class_type(): ERROR, no class in class pool/n");
	}
	
	unlock();
	
	type = (u32)current;
	
	return type;
}

static void init_parent_object(ClassType *current, void *object)
{
	if( current )
	{
		if( current->parent )
			init_parent_object(current->parent, object);
		
		if( current->init_object )
			current->init_object(object);
	}
}

void* g_object_new(u32 class_type)
{
	ClassType *pclass = NULL;
	void *object = NULL;
	
	if( class_type == 0 )
		return NULL;

	pclass = (ClassType*)class_type;
	object = malloc(pclass->object_size);
	
	if( object )
	{
		((CObject*)object)->vclass = pclass->vclass;
		init_parent_object(pclass, object);
	}
	
	return object;
}

CObject* g_type_check_instance_cast(CObject *obj, u32 classtype)
{
	ClassType *pclass,*dest_class;
	
	if( obj == NULL || classtype == 0 )
		return NULL;
	
	if( obj->vclass == NULL )
		return NULL;

	dest_class = (ClassType*)classtype;
	pclass = (ClassType*)obj->vclass->class_type;
	
	while(pclass)
	{
		if( pclass == dest_class )
			return obj;
		pclass = pclass->parent;
	}

	return NULL;
}

CObjectClass* g_type_check_class_cast(CObjectClass *vclass, u32 classtype)
{
	ClassType *pclass,*dest_class;
	
	if( vclass == NULL || classtype == 0 )
		return NULL;

	dest_class = (ClassType*)classtype;
	pclass = (ClassType*)vclass->class_type;
	
	while(pclass)
	{
		if( pclass == dest_class )
			return vclass;
		pclass = pclass->parent;
	}

	return NULL;
}

cbool g_type_check_instance_is_a(CObject *obj, u32 classtype)
{
	ClassType *pclass,*dest_class;
	
	if( obj == NULL || classtype == 0 )
		return false;
	
	if( obj->vclass == NULL )
		return false;

	dest_class = (ClassType*)classtype;
	pclass = (ClassType*)obj->vclass->class_type;
	
	while(pclass)
	{
		if( pclass == dest_class )
			return true;
		pclass = pclass->parent;
	}

	return false;
}

cbool g_type_check_class_is_a(CObjectClass *vclass, u32 classtype)
{
	ClassType *pclass,*dest_class;
	
	if( vclass == NULL || classtype == 0 )
		return false;

	dest_class = (ClassType*)classtype;
	pclass = (ClassType*)vclass->class_type;
	
	while(pclass)
	{
		if( pclass == dest_class )
			return true;
		pclass = pclass->parent;
	}

	return false;
}

CObjectClass* g_type_get_instance_class(CObject *obj, u32 classtype)
{
	ClassType *pclass,*dest_class;
	
	if( obj == NULL || classtype == 0 )
		return NULL;
	
	if( obj->vclass == NULL )
		return NULL;

	dest_class = (ClassType*)classtype;
	pclass = (ClassType*)obj->vclass->class_type;

	while(pclass)
	{
		if(pclass == dest_class)
			return obj->vclass;
		pclass = pclass->parent;
	}
	
	return NULL;
}

CObjectClass* g_type_class_peek_parent(CObjectClass* vclass)
{
	ClassType *pclass = NULL;
	CObjectClass *parent_class = NULL;
	
	if( vclass == NULL )
		return NULL;
	
	pclass = (ClassType*)vclass->class_type;
	return pclass->parent->vclass;
	
}